﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Threading;
using Faz.SideWinderSC.Logic;

namespace Faz.SideWinderSC.Client.ViewModel
{
    /// <summary>
    /// Defines the view-model to manage th mapping of a Strategic Commander controller.
    /// </summary>
    public class SwscViewModel : AbstractViewModel, IDisposable
    {
        /// <summary>
        /// The encapsulated controller.
        /// </summary>
        private readonly SwscController controller;

        /// <summary>
        /// The active buttons.
        /// </summary>
        private readonly ICollection<SwscButton> activeButtons;

        /// <summary>
        /// The WPF dispatcher retrieved during the creation of the view model instance.
        /// </summary>
        private readonly Dispatcher dispatcher;

        /// <summary>
        /// Initializes a new instance of the <see cref="SwscViewModel"/> class.
        /// </summary>
        /// <param name="controller">The encapsulated controller.</param>
        public SwscViewModel(SwscController controller)
        {
            this.controller = controller;

            this.dispatcher = Dispatcher.CurrentDispatcher;

            this.activeButtons = new ObservableCollection<SwscButton>();

            this.controller.ButtonDown += this.OnButtonChanged;
            this.controller.ButtonUp += this.OnButtonChanged;

            this.controller.Initialize();
        }

        /// <summary>
        /// Gets the active buttons.
        /// </summary>
        public ICollection<SwscButton> ActiveButtons
        {
            get { return this.activeButtons; }
        }

        /// <summary>
        /// Gets or sets the selected mapping.
        /// </summary>
        public MappingViewModel SelectedMapping
        {
            get { return this.GetValue<MappingViewModel>("SelectedMapping"); }
            set { this.SetValue("SelectedMapping", value); }
        }

        /// <summary>
        /// Disposes the encapsulated resources.
        /// </summary>
        public void Dispose()
        {
            this.controller.Dispose();
        }

        /// <summary>
        /// Called when a property is updated.
        /// </summary>
        /// <param name="propertyName">The name of he updated property.</param>
        protected override void OnPropertyChanged(string propertyName)
        {
            base.OnPropertyChanged(propertyName);

            if (propertyName == "SelectedMapping")
            {
                if (this.SelectedMapping == null)
                {
                    this.controller.SetLights();
                }
                else
                {
                    SwscLight? light = this.SelectedMapping.Button.ToLight(true);
                    if (light.HasValue)
                    {
                        this.controller.SetLights(light.Value);
                    }
                }
            }
        }

        /// <summary>
        /// Called when a button is pressed or released.
        /// </summary>
        /// <param name="sender">The parameter is not used.</param>
        /// <param name="e">The details of the event.</param>
        private void OnButtonChanged(object sender, ButtonEventArgs e)
        {
            // Update ActiveButtons
            if (e.IsDown)
            {
                dispatcher.Invoke(new Action<SwscButton>(this.ActiveButtons.Add), e.Button);
            }
            else
            {
                dispatcher.Invoke(new Func<SwscButton, bool>(this.ActiveButtons.Remove), e.Button);
            }
        }
    }
}
